#include "FlowChart.h"
#include "Session.h"
#include "LGProto.h"
#include "GateServer.h"
#include "../../include/GTProto.h"
#include "EndianCast.h"
#include "../AccountVerify/AccountVerify.h"
#include <boost/bind.hpp>
#include "ut_debug.h"

/************************************************************************/
/* CFSM class                                                           */
/************************************************************************/
CFSM::CFSM( CSession * pSessin)
{
    m_pSession = pSessin;
}

void CFSM::OnLoginReq( std::string strUserName, std::string strPwd )
{
    state_cast<const IEvents &>().OnLoginReq(strUserName, strPwd);
    process_event(CEvValidateBegin());
}

void CFSM::OnRcvValidationResult( std::string strUser, bool bResult, uint32 nUserID )
{
    state_cast<const IEvents &>().OnRcvValidationResult(strUser, bResult, nUserID);
}

void CFSM::ValidateUserInfo( std::string strUserName, std::string strPwd ) const
{
    CAccountVerify::Instance()->Verify(
        strUserName.c_str(), 
        strPwd.c_str(), 
        boost::bind(&CFSM::OnRcvValidationResult, const_cast<CFSM * const>(this), _1, _2, _3));
}

CSession * CFSM::GetSession() const
{
    return m_pSession;
}

/************************************************************************/
/* class CWaitLoginState                                                */
/************************************************************************/
CWaitLoginState::CWaitLoginState()
{
    LOG(DEBUGINFO) << "CWaitLoginState";
    m_tStartTime = time(NULL);
    CMinuteTimer::Instance()->Subscribe(this);
}

CWaitLoginState::~CWaitLoginState()
{
    CMinuteTimer::Instance()->UnSubscribe(this);
}

void CWaitLoginState::OnLoginReq( std::string strUserName, std::string strPwd ) const
{
    context<CFSM>().ValidateUserInfo(strUserName, strPwd);
}

void CWaitLoginState::OnTrigger( time_t tNow)
{
    if (tNow - m_tStartTime > 60)
    {
        if (CSession * pSession = context<CFSM>().GetSession())
            pSession->Disconnect();
    }

}

/************************************************************************/
/* class CWaitValidationState                                           */
/************************************************************************/
uint32 CWaitValidationState::nToken = 0;

CWaitValidationState::CWaitValidationState()
{
    LOG(DEBUGINFO) << "CWaitValidationState";
    m_tStartTime = time(NULL);
    CMinuteTimer::Instance()->Subscribe(this);
}

CWaitValidationState::~CWaitValidationState()
{
    LOG(DEBUGINFO) << __FUNCTION__;
    CMinuteTimer::Instance()->UnSubscribe(this);
}

void CWaitValidationState::OnRcvValidationResult( std::string strUser, bool bResult, uint32 nUserID ) const 
{
    PKG_LOGIN_ACK ack;
    
    if (bResult)
    {
        ack.set_error_code(0);
        ack.set_user_id(nUserID);
        if (CGateServer * pGateserver = CGateServerMgr::Instance()->GetMinLoadGT())
        {
            ack.set_gate_ip(pGateserver->GetIpAddress());
            ack.set_gate_port(pGateserver->GetPort());
            ack.set_token(nToken);
            GT_USER_TOKEN_NTF_PKG pkg;
            pkg.nUserID = htonl(nUserID);
            pkg.nToken = htonl(nToken++);
            pGateserver->Send(GT_USER_TOKEN_NTF_ID, &pkg, sizeof(pkg));
        }
    }
    else
    {
        ack.set_error_code(1);
    }

    if (CSession * pSession = context<CFSM>().GetSession())
    {
        pSession->Send(LOGIN_ACK, &ack);
    }
}

void CWaitValidationState::OnTrigger( time_t tNow)
{
    if (tNow - m_tStartTime > 20)
    {
        if (CSession * pSession = context<CFSM>().GetSession())
            pSession->Disconnect();
    }
}
